package many_one

import (
	"app/out"
	"sync"
)

// Task 表示一个任务实例
type Task struct {
	ID int64
}

// run 任务的方法，表示执行这个任务
func (t *Task) run() {
	out.Input(t.ID)
}

const taskNum int64 = 1000

// producer 生产者向通道写入taskNum个Task
func producer(taskCh chan<- Task, start, size int64) {
	var i int64
	for i = start; i < start+size; i++ {
		taskCh <- Task{
			ID: i,
		}
	}
}

// consumer 消费者读取通道中的Task，然后调用Task.run执行任务
func consumer(taskCh <-chan Task) {
	for task := range taskCh {
		task.run()
	}
}

var taskCh = make(chan Task, 10)

// Exec 执行生产者、消费者
func Exec() {
	var wg sync.WaitGroup //阻塞整个函数，直到生产、消费全部完成

	var pwg sync.WaitGroup //标识生产者结束，这时close
	//100个生产者（10000个任务，每100个任务建立一个协程）
	var i int64
	for i = 0; i < taskNum; i += 100 {
		wg.Add(1) //生产者计数
		pwg.Add(1)
		go func(i int64) {
			defer wg.Done()
			defer pwg.Done()
			//这里做了一个传值，是因为多个协程访问了一个变化的i。传值会将当前的i值作为形参，复制一份传入函数
			producer(taskCh, i, 100)
		}(i)
	}
	//1个消费者
	wg.Add(1)
	go func() {
		wg.Done()
		consumer(taskCh)
	}()

	//这里比较复杂的就是何时关闭通道，等待生产者全部结束，再关闭
	pwg.Wait()
	close(taskCh)

	wg.Wait()

}
